import { Injectable } from '@angular/core';
import { g } from './global-data'

@Injectable({
    providedIn: 'root'
})
export class TransformService {
    get_x_from_longitude(lon: number): number {
        // 将经度-180度~180度之间的值归一化为0~1之间的实数，经度0度对应值为0.5，西经180度对应值为0，东经180度对应值为1
        return (lon + 180.0) / 360.0;
    }

    get_y_from_latitude(lat: number): number {
        // 将纬度大约-85.05度~85.05度之间的值归一化为1~0之间的实数，北纬85.05度对应值约为0，赤道对应值为0.5，南纬85.05度对应值约为1
        return (1 - Math.log(Math.tan(lat * Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2;
    }
        
    get_fpx_from_longitude(lon: number): number {
        // 将经度-180度~180度之间的值转换为Web墨卡托投影像素坐标系中的全图像素横坐标
        return Math.floor(g.FULL_MAP_WIDTH * (lon + 180.0) / 360.0);
    }
        
    get_fpy_from_latitude(lat: number): number {
        // 将纬度大约-85.05度~85.05度之间的值转换为Web墨卡托投影像素坐标系中的全图像素纵坐标
        return Math.floor(g.FULL_MAP_WIDTH * (1 - Math.log(Math.tan(lat * Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2);
    }

    get_longitude_from_x(x: number): number {
        return x * 360.0 - 180.0 ;
    }

    get_latitude_from_y(y: number): number {
        // Transform a y coordinate into a latitude
        const n = Math.PI * (1 - 2 * y);
        return 180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
    }

    get_longitude_from_fpx(fpx: number): number {
        // Transform an x coordinate into a longitude
        const x = fpx / g.FULL_MAP_WIDTH;
        return x * 360.0 - 180.0;
    }

    get_latitude_from_fpy(fpy: number): number {
        // Transform a y coordinate into a latitude
        const y = fpy / g.FULL_MAP_WIDTH;
        const n = Math.PI * (1 - 2 * y);
        return 180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
    }

    get_px_from_fpx(fpx: number, zoom: number): number {
        return fpx >> (g.MAX_ZOOM - zoom);
    }
        
    get_py_from_fpy(fpy: number, zoom: number): number {
        return fpy >> (g.MAX_ZOOM - zoom);
    }

    get_fpx_from_px(px: number, zoom: number) {
        return px << (g.MAX_ZOOM - zoom);
    }
        
    get_fpy_from_py(py: number, zoom: number) {
        return py << (g.MAX_ZOOM - zoom);
    }

    compute_radian_between(lon1: number, lat1: number, lon2: number, lat2: number) {
        const TO_RADIANS = Math.PI / 180.0;
        lon1 *= TO_RADIANS;
        lat1 *= TO_RADIANS;
        lon2 *= TO_RADIANS;
        lat2 *= TO_RADIANS;

        // Formula given by Wikipedia: Great - circle_distance as follows:
        // angle = 2 arcsin(sqrt((sin((lat2 - lat1) / 2))^^2 + cos(lat1) + cos(lat2)(sin((lon2 - lon1) / 2))^^2))
        const first_sine = Math.sin((lat2 - lat1) / 2.0);
        const second_sine = Math.sin((lon2 - lon1) / 2.0);
        const term2 = Math.cos(lat1) * Math.cos(lat2) * second_sine * second_sine;
        return 2 * Math.asin(Math.sqrt(first_sine * first_sine + term2))
    }

    // 计算点到线段的距离
    point_to_line_distance(px: number, py: number, x1: number, y1: number, x2: number, y2: number) {
        const A = px - x1;
        const B = py - y1;
        const C = x2 - x1;
        const D = y2 - y1;

        const dot = A * C + B * D;
        const len_sq = C * C + D * D;
        let param = -1;

        if (len_sq !== 0) {
            param = dot / len_sq;
        }

        let xx, yy;

        if (param < 0) {
            xx = x1;
            yy = y1;
        } else if (param > 1) {
            xx = x2;
            yy = y2;
        } else {
            xx = x1 + param * C;
            yy = y1 + param * D;
        }

        const dx = px - xx;
        const dy = py - yy;

        return Math.sqrt(dx * dx + dy * dy);
    }

    utc2local(utc: string) {
        const date: any = new Date(utc);

        const y = date.getFullYear();
        const m = date.getMonth() + 1;
        const m_str = m < 10 ? ('0' + m) : m;
        const d = date.getDate();
        const d_str = d < 10 ? ('0' + d) : d;
        const h = date.getHours();
        const h_str = h < 10 ? ('0' + h) : h;
        const minute = date.getMinutes();
        const second = date.getSeconds();
        const minute_str = minute < 10 ? ('0' + minute) : minute;
        const second_str = second < 10 ? ('0' + second) : second;
        
        return y + '-' + m_str + '-' + d_str + ' ' + h_str + ':' + minute_str + ':' + second_str;
    }

}
